package com.ivo.activiti.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ivo.activiti.bpmn.ProcessService;
import javafx.beans.binding.ObjectExpression;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wj
 * @version 1.0
 */
@RestController
@RequestMapping("/process")
public class ProcessController {

    @Resource
    private ProcessService processService;

    /**
     * 获取流程定义
     */
    @GetMapping("/processDefinition")
    public List processDefinition() {
        List<ProcessDefinition> processDefinitionList = processService.getProcessDefinitions();
        List<Map<String, Object>> mapList = new ArrayList<>();
        for(ProcessDefinition processDefinition : processDefinitionList) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", processDefinition.getId());
            map.put("category", processDefinition.getCategory());
            map.put("name", processDefinition.getName());
            map.put("key", processDefinition.getKey());
            map.put("description", processDefinition.getDescription());
            map.put("version", processDefinition.getVersion());
            map.put("resourceName", processDefinition.getResourceName());
            map.put("deploymentId", processDefinition.getDeploymentId());
            map.put("diagramResourceName", processDefinition.getDiagramResourceName());
            map.put("hasStartFormKey", processDefinition.hasStartFormKey());
            map.put("hasGraphicalNotation", processDefinition.hasGraphicalNotation());
            map.put("isSuspended", processDefinition.isSuspended());
            map.put("tenantId", processDefinition.getTenantId());
            map.put("engineVersion", processDefinition.getEngineVersion());
            map.put("appVersion", processDefinition.getAppVersion());
            mapList.add(map);
        }
        return mapList;
    }

    /**
     * 启动流程
     * @param key KEY
     */
    @PostMapping("/processStart")
    public String processStart(String key) {
        processService.processStart(key);
        return "ok";
    }

    /**
     * 获取流程实例
     */
    @GetMapping("/processInstance")
    public List processInstance() {
        List<ProcessInstance> processInstanceList = processService.getProcessInstances();
        List<Map<String, Object>> mapList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        for(ProcessInstance processInstance : processInstanceList) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", processInstance.getId());
            map.put("processDefinitionId", processInstance.getProcessDefinitionId());
            map.put("processDefinitionName", processInstance.getProcessDefinitionName());
            map.put("processDefinitionKey", processInstance.getProcessDefinitionKey());
            map.put("processDefinitionVersion", processInstance.getProcessDefinitionVersion());
            map.put("businessKey", processInstance.getBusinessKey());
            map.put("suspended", processInstance.isSuspended());
            map.put("tenantId", processInstance.getTenantId());
            map.put("name", processInstance.getName());
            map.put("description", processInstance.getDescription());
            map.put("startTime", sdf.format(processInstance.getStartTime()));
            map.put("startUserId", processInstance.getStartUserId());
            map.put("appVersion", processInstance.getAppVersion());
            mapList.add(map);
        }
        return mapList;
    }

    /**
     * 获取流程实例的流程图
     * @param processInstanceId 流程实例
     */
    @RequestMapping("/processInstanceDiagram")
    public void diagram(String processInstanceId, HttpServletResponse response) {
        InputStream in = processService.getResourceAsStream(processInstanceId);
        if(in == null) return;
        // 输出流程图
        byte[] b = new byte[2048];
        int len;
        try {
            ServletOutputStream outputStream = response.getOutputStream();
            while ((len = in.read(b, 0, b.length)) != -1) {
                outputStream.write(b, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 高亮流程实例经过的路径
     * @param processInstanceId 单号
     */
    @RequestMapping("/historicActivity")
    public Map historicActivity(String processInstanceId) {
        return processService.historicActivity(processInstanceId);
    }

    /**
     * 执行任务
     * @param processInstanceId 流程实例
     */
    @RequestMapping("/completeTask")
    public String completeTask(String processInstanceId, String variables) {
        Map<String, Object> map = new HashMap<>();
        if(StringUtils.isNotEmpty(variables)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                map = objectMapper.readValue(variables, new TypeReference<Map<String, Object>>() {});
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        processService.completeTask(processInstanceId, map);
        return "ok";
    }

    /**
     * 获取历史任务
     * @param processInstanceId 流程实例ID
     * @return List
     */
    @GetMapping("/getHistoryTask")
    public List getHistoryTask(String processInstanceId) {
       List<HistoricTaskInstance> taskList = processService.getHistoricTasks(processInstanceId);
       List<Map<String, Object>> mapList = new ArrayList<>();
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
       for(HistoricTaskInstance task : taskList) {
           Map<String, Object> map  = new HashMap<>();
           map.put("deleteReason", task.getDeleteReason());
           map.put("startTime", formatDate(task.getStartTime()));
           map.put("endTime", formatDate(task.getEndTime()));
           map.put("durationInMillis", task.getDurationInMillis());
           map.put("workTimeInMillis", task.getWorkTimeInMillis());
           map.put("claimTime", formatDate(task.getClaimTime()));
           map.put("id", task.getId());
           map.put("name", task.getName());
           map.put("description", task.getDescription());
           map.put("priority", task.getPriority());
           map.put("owner", task.getOwner());
           map.put("assignee", task.getAssignee());
           map.put("executionId", task.getExecutionId());
           map.put("createTime", formatDate(task.getCreateTime()));
           map.put("dueDate", formatDate(task.getDueDate()));
           map.put("category", task.getCategory());
           map.put("parentTaskId", task.getParentTaskId());
           mapList.add(map);
       }
       return mapList;
    }

    /**
     * 获取历史Activity
     * @param processInstanceId 流程实例ID
     * @return List
     */
    @GetMapping("/getHistoricActivity")
    public List getHistoricActivity(String processInstanceId) {
        List<HistoricActivityInstance> activityList = processService.getHistoricActivitys(processInstanceId);
        List<Map<String, Object>> mapList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        for(HistoricActivityInstance activity : activityList) {
            Map<String, Object> map  = new HashMap<>();
            map.put("id", activity.getId());
            map.put("activityId", activity.getActivityId());
            map.put("activityName", activity.getActivityName());
            map.put("activityType", activity.getActivityType());
            map.put("executionId", activity.getExecutionId());
            map.put("assignee", activity.getAssignee());
            map.put("startTime", formatDate(activity.getStartTime()));
            map.put("endTime", formatDate(activity.getEndTime()));
            map.put("durationInMillis", activity.getDurationInMillis());
            map.put("deleteReason", activity.getDeleteReason());
            map.put("time", formatDate(activity.getTime()));
            mapList.add(map);
        }
        return mapList;
    }

    /**
     * 获取流程参数
     * @param processInstanceId 流程实例
     * @return List
     */
    @GetMapping("/getProcessVariables")
    public List getProcessVariables(String processInstanceId) {
        Map<String, Object> variables = processService.getProcessVariables(processInstanceId);
        List<Map<String, Object>> list = new ArrayList<>();
        for(String val : variables.keySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", val);
            map.put("value", variables.get(val));
            list.add(map);
        }
        return list;
    }

    /**
     * 获取任务参数
     * @param processInstanceId 流程实例
     * @return List
     */
    @GetMapping("/getTaskVariables")
    public List getTaskVariables(String processInstanceId) {
        Map<String, Object> variables = processService.getTaskVariables(processInstanceId);
        List<Map<String, Object>> list = new ArrayList<>();
        for(String val : variables.keySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", val);
            map.put("value", variables.get(val));
            list.add(map);
        }
        return list;
    }

    public String formatDate(Date date) {
        if(date == null) return null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return sdf.format(date);
    }

    /**
     * 任务驳回
     * @param processInstanceId 流程实例ID
     */
    @RequestMapping("/rejectTask")
    public String rejectTask(String processInstanceId) {
        processService.rejectTask(processInstanceId);
        return "ok";
    }
}
